# 类图元素定义
from typing import Dict, Set
import warnings
# mermaid关键字
keyword=set([
    'teststr', 'pipe', 'down', 'num', 
    'comma', 'alpha', 'colon', 'minus',
    'brkt', 'dot', 'punctuation', 
    'unicode_text', 'plus', 'equals', 
    'mult', 'underscore','end',
    'link','class','call','click'
])

def name_handler(p: str)->str:
    p=p.strip().lower()
    if p in keyword:
        p+='_'
    return p.replace('.','_')

class Symbol:
    '''标识符
    是所有类图元素的父类
    定义了__hash__函数和__eq__函数
    主要是为了方便加入集合或字典里
    '''

    def __init__(self, o: str) -> None:
        if not o:
            raise ValueError("名称不能为空值")
        if isinstance(o, str):
            self.name = name_handler(o)
            return
        warnings.warn("Symbol的name只能为字符串")

    def __hash__(self) -> int:
        '''哈希函数'''
        return hash(self.name)

    def __eq__(self, __o: object) -> bool:
        '''判断相等'''
        if type(self) == type(__o):
            return self.name == __o.name
        return False

    pass


class Method(Symbol):
    '''类方法'''

    def __init__(self, name: str) -> None:
        super().__init__(name)
        self.paras: Set[str] = set()

    def addPara(self, para: object) -> None:
        if para:
            if isinstance(para, str):
                self.paras.add(name_handler(para))
            elif isinstance(para, set):
                self.paras = self.paras | para
            else:
                warnings.warn('para添加的参数类型不匹配')
        else:
            warnings.warn('添加的参数为None')

    def __iadd__(self, other):
        '''合并方法,会把参数合并'''
        if isinstance(other, Method):
            if self.name != other.name:
                raise ValueError("方法名一样才可以合并")
            self.paras = self.paras | other.paras
            return self
        warnings.warn("应为Method类型")

    def __str__(self) -> str:
        return f'\t{self.name}({",".join(self.paras)})'

    pass


class Attr(Symbol):
    '''类属性'''

    def __init__(self, name: str) -> None:
        super().__init__(name)

    def __str__(self) -> str:
        return f'\t{self.name}'

    pass


class Class(Symbol):
    '''类定义'''

    def __init__(self, name: str) -> None:
        super().__init__(name)
        self.methods: Dict[str, Method] = dict()
        self.attrs: Dict[str, Attr] = dict()
        self.superClasses: Set[str] = set()
        # 默认要过滤
        self.filter = True

    def addMethod(self, method: Method) -> None:
        if method:
            if method.name in self.methods:
                self.methods[method.name] += method
                return
            if method.name:
                self.methods[method.name] = method
        else:
            warnings.warn('添加的方法为None')

    def setAttr(self, name: str) -> None:
        '''设置名为name的属性'''
        if name:
            a = Attr(name)
            if a.name:
                self.attrs[a.name] = a
        else:
            warnings.warn('添加的属性为None')

    def addInterface(self, interface: str) -> None:
        '''实现接口interface'''
        # 为了方便一起加在了superClasses里
        # 加个interface$前缀作为接口的标记
        interface = name_handler(interface)
        self.inherit('interface$'+interface)
        pass

    def inherit(self, className: str) -> None:
        '''继承'''
        if className:
            className = name_handler(className)
            if className != self.name:
                self.superClasses.add(className)
            else:
                warnings.warn('类继承了自己')
        else:
            warnings.warn('继承的父类为None')

    def __iadd__(self, other):
        '''合并类,取两个类属性和方法的并集'''
        if isinstance(other, Class):
            if self.name != other.name:
                raise ValueError("类名一样才可以合并")
            for m in other.methods:
                self.addMethod(other.methods[m])
            self.attrs.update(other.attrs)
            self.superClasses = self.superClasses | other.superClasses
            return self

        warnings.warn("应为Class类型")

    def __str__(self):
        if bool(self.methods) or bool(self.attrs):
            separator = '\n'
            return f'''
class {self.name}{{
{separator.join(map(lambda k: str(self.attrs[k]), self.attrs))}
{separator.join(map(lambda k: str(self.methods[k]), self.methods))}
}}
'''
        return ''
    pass

# 特别说明
# 合并方法和类用 += 前提是类名或方法名一样
# 合并类会把属性和方法合并
# 方法合并会把参数合并
